package com.ruoyi.car.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.car.controller.admin.CarCustomer.vo.CarCustomerResp;
import com.ruoyi.car.controller.admin.carinfo.vo.*;
import com.ruoyi.car.entity.CarInfo;
import com.ruoyi.car.entity.CarInfoPhoto;
import com.ruoyi.car.es.service.EsCarInfoService;
import com.ruoyi.car.mapper.CarCustomerMapper;
import com.ruoyi.car.mapper.CarInfoPhotoMapper;
import com.ruoyi.car.mapstruct.CarInfoConvert;
import com.ruoyi.car.service.CarInfoPhotoService;
import com.ruoyi.car.service.CarInfoService;
import com.ruoyi.car.mapper.CarInfoMapper;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author 11452
* @description 针对表【car_info(车辆信息)】的数据库操作Service实现
* @createDate 2023-06-08 09:37:18
*/
@Log4j2
@Service
public class CarInfoServiceImpl extends ServiceImpl<CarInfoMapper, CarInfo>
    implements CarInfoService{

    @Autowired
    private CarInfoMapper carInfoMapper;

    @Autowired
    private CarCustomerMapper carCustomerMapper;


    /**
     * 汽车图片
     */
    @Autowired
    private CarInfoPhotoService carInfoPhotoService;

    /**
     * json序列化和反列化工具,Jackson2框架
     */
    @Autowired
    private ObjectMapper  objectMapper;

    @Autowired
    private RedisTemplate redisTemplate;



    @Override
    public PageInfo<CarInfoResp> search(CarInfoReq req) {

        return   PageHelper.startPage(req.getPage(),req.getSize())
                  .doSelectPageInfo(()->{

                      //读取缓存
                      //客户类型
                      List<SysDictData>   customerClassList= DictUtils.getDictCache("customer_class");
                      //新能源缓存
                      List<SysDictData>  vehiclesList=DictUtils.getDictCache("new_energy_vehicles");


                      //查询结果
                      List<CarInfoResp> list = carInfoMapper.search(req);
                      //自定义其它数据查询
                      for(CarInfoResp resp: list){

                          //计算两个日期相差的天数 年检到期时间  结束时间-今天日期>0 还未到    <0已超过时间
                          LocalDate start =LocalDate.now();
                          if(resp.getInspectionDate()!=null){
                              LocalDate end= resp.getInspectionDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                              long day=end.toEpochDay() - start.toEpochDay();
                              //超过年检时间，就不要本周提示了
                              if(day>0 && day<=60){
                                  resp.setInspectionDay((int) day);
                              }
                          }

                          //计算保险到期时间
                          if(resp.getInsuranceDate()!=null){
                              LocalDate end= resp.getInsuranceDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                              long day=end.toEpochDay() - start.toEpochDay();
                              //超过保险时间，就不要本周提示了
                              if(day>0 && day<=60){
                                  resp.setInsuranceDay((int) day);
                              }
                          }


                          //客户类型名称
                          Optional<String> stringCustomer = customerClassList.stream()
                                  .filter(f -> f.getDictValue().equals(resp.getCusCateId()))
                                  .map(SysDictData::getDictLabel)
                                  .findFirst();
                          if(stringCustomer.isPresent()){
                              resp.setCusCateName(stringCustomer.get());
                          }

                          //填充 新能源名称  newEnergyVehiclesName
                          Optional<String> engrgyOptional = vehiclesList.stream()
                                  .filter(f -> f.getDictValue().equals(resp.getNewEnergyVehicles()))
                                  .map(SysDictData::getDictLabel)
                                  .findFirst();
                          if(engrgyOptional.isPresent()){
                              resp.setNewEnergyVehiclesName(engrgyOptional.get());
                          }

                          //动态扩展attributes  转换   List<Map>
                          String attr=resp.getAttributes();
                          if(StringUtils.isNotBlank(attr)){
                              //转为java对象 List<Map> attributesList

                              //List<Map>
                              JavaType javaType=objectMapper.getTypeFactory().constructParametricType(List.class, CarInfoProperties.class);
                               try {
                                 List<CarInfoProperties> listMap= objectMapper.readValue(attr, javaType);
                                 resp.setAttributesList(listMap);
                              } catch (JsonProcessingException e) {
                                 log.error(e);
                                 throw new ServiceException(MessageUtils.message("json.processing.exception"));
                              }
                          }


                          //汽车图片 carInfoPhotoList
                          LambdaQueryWrapper<CarInfoPhoto>  photoQueryWrap=new LambdaQueryWrapper<>();
                          photoQueryWrap.eq(CarInfoPhoto::getCarId, resp.getId());
                          List<CarInfoPhoto> carInfoPhotos = carInfoPhotoService.list(photoQueryWrap);
                          resp.setCarInfoPhotoList(carInfoPhotos);
                      }

                  });

    }

    /**
     * 新增车辆
     * @param req
     * @return
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    @Override
    public boolean add(CarInfoAddReq req) {
        //同一个门店，同一个车牌号只允许出现一次
        LambdaQueryWrapper<CarInfo> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(CarInfo::getDeptId,req.getDeptId()).eq(CarInfo::getCarNo,req.getCarNo());
        Long count = this.carInfoMapper.selectCount(queryWrapper);
        if(count>0){
            throw new ServiceException(MessageUtils.message(MessageUtils.message("carinfo.carno.exists")));
        }

        //保存汽车信息
        CarInfo carInfo= CarInfoConvert.INSTANCE.convert(req);
        //扩展属性变为json
        try {
            String jsonStr = objectMapper.writeValueAsString(req.getAttributesList());
            carInfo.setAttributes(jsonStr);
        }catch(Exception e){
            log.error(e);
            throw new ServiceException(MessageUtils.message("carinfo.json.error"));
        }

         this.carInfoMapper.insert(carInfo);

        //保存图片信息
        List<CarInfoPhotoReq> carInfoPhotoList = req.getCarInfoPhotoList();
        if( carInfoPhotoList!=null && carInfoPhotoList.size()>0){

            List<CarInfoPhoto> photoList=new ArrayList<>();
            for(CarInfoPhotoReq  photoReq : carInfoPhotoList){
                CarInfoPhoto carInfoPhoto=CarInfoConvert.INSTANCE.convert(photoReq);
                //赋值汽车ID
                carInfoPhoto.setCarId( carInfo.getId());
                photoList.add(carInfoPhoto);
            }
            //批量新增
            this.carInfoPhotoService.saveBatch(photoList);
        }

        //维护过滤器的名单
        String redisKey="carinfo:filter:set";
        this.redisTemplate.opsForSet().add(redisKey,carInfo.getId());


        return true;
    }

    /**
     * 程序启动时候，预热数据(现在数据量很小，如果数据量大了，你采用bloom过滤)
     */
    @PostConstruct
    public void initCarInfoToHashSet(){
        //这里不要使用list，没有办法判断值在不在list里面
        Set<Long> ids=this.carInfoMapper.selectIds();
        //写入到redis中
        String redisKey="carinfo:filter:set";
        this.redisTemplate.opsForSet().add(redisKey,ids.toArray());
    }


    /**
     * 根据id查询汽车信息，汽车信息，4-5个月或者1万公里才会来保养一次
     * @param id
     * @return
     */
    @Override
    public CarInfoDetailResp findById(Long id) {
 //       布隆过滤器   Redisson框架
//        RBloomFilter<Object> bloomFilter = this.redissonClient.getBloomFilter("car_info:filter");
//        boolean contains = bloomFilter.contains(id);
//        if(!contains){
//            throw new ServiceException(id+"，缓存穿透了.....");
//        }

        //数据量比较小，先去set中判断id是否存在，如果不存在，直接返回  过滤
        String redisKeyHash="carinfo:filter:set";
        if(!this.redisTemplate.opsForSet().isMember(redisKeyHash,id)){
            throw new ServiceException(id+"，缓存穿透了.....");
        }

        //先查询redis
        String redisKey="car:info:"+id;
        Object redisValue=redisTemplate.opsForValue().get(redisKey);
        if(Objects.nonNull(redisValue)){
            CarInfoDetailResp cache= (CarInfoDetailResp) redisValue;
            return cache;
        }


        CarInfoDetailResp db= this.carInfoMapper.findById(id);
        if(db==null){
            //移出键，在数据库中不存在
            this.redisTemplate.opsForSet().remove(redisKeyHash,id);
            //国际化 i18n 中查询
            String msg= MessageUtils.message("db.not.found");
            throw new ServiceException(msg);
        }
        //把字符串转换为json
        //动态扩展attributes  转换   List<Map>
        String attr=db.getAttributes();
        if(StringUtils.isNotBlank(attr)){
            //转为java对象 List<Map> attributesList
            //List<Map>
            JavaType javaType=objectMapper.getTypeFactory().constructParametricType(List.class, CarInfoProperties.class);
            try {
                List<CarInfoProperties> listMap= objectMapper.readValue(attr, javaType);
                db.setAttributesList(listMap);
            } catch (JsonProcessingException e) {
                log.error(e);
                throw new ServiceException(MessageUtils.message("json.processing.exception"));
            }
        }else{
            db.setAttributesList(new ArrayList<CarInfoProperties>());
        }

        //汽车图片 carInfoPhotoList
        LambdaQueryWrapper<CarInfoPhoto>  photoQueryWrap=new LambdaQueryWrapper<>();
        photoQueryWrap.eq(CarInfoPhoto::getCarId, db.getId());
        List<CarInfoPhoto> carInfoPhotos = carInfoPhotoService.list(photoQueryWrap);

        //转换
        List<CarInfoPhotoResp> arr=new ArrayList<>();
        if(carInfoPhotos!=null && carInfoPhotos.size()>0){
            for(CarInfoPhoto p: carInfoPhotos){
                CarInfoPhotoResp cp=CarInfoConvert.INSTANCE.convert(p);
                arr.add(cp);
            }
        }
        db.setCarInfoPhotoList(arr);

        //保存到redis缓存中
        this.redisTemplate.opsForValue().set(redisKey,db);
        return db;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean edit(CarInfoEditReq req) {

        CarInfo db= this.carInfoMapper.selectById(req.getId());
        if(db==null){
            //国际化 i18n 中查询
            String msg= MessageUtils.message("db.not.found");
            throw new ServiceException(msg);
        }

        //覆盖值
       CarInfo carInfo= CarInfoConvert.INSTANCE.convert(req);

        //扩展属性变为json
        try {
            String jsonStr = objectMapper.writeValueAsString(req.getAttributesList());
            carInfo.setAttributes(jsonStr);
        }catch(Exception e){
            log.error(e);
            throw new ServiceException(MessageUtils.message("carinfo.json.error"));
        }

        int count = this.carInfoMapper.updateById(carInfo);
        if(count==0){
            String msg= MessageUtils.message("database.save.error");
            throw new ServiceException(msg);
        }

        //保存图片信息
        List<CarInfoPhotoReq> carInfoPhotoList = req.getCarInfoPhotoList();
        if( carInfoPhotoList!=null && carInfoPhotoList.size()>0){
            //只处理新增的图片
            List<CarInfoPhotoReq> collect = carInfoPhotoList.stream().filter(p -> p.getId() == null).collect(Collectors.toList());

            List<CarInfoPhoto> photoList=new ArrayList<>();
            for(CarInfoPhotoReq  photoReq : collect){
                CarInfoPhoto carInfoPhoto=CarInfoConvert.INSTANCE.convert(photoReq);
                //赋值汽车ID
                carInfoPhoto.setCarId( carInfo.getId());
                photoList.add(carInfoPhoto);
            }
            //批量新增
            if(photoList.size()>0) {
                this.carInfoPhotoService.saveBatch(photoList);
            }
        }

        //移出缓存
        String redisKey="car:info:"+req.getId();
        this.redisTemplate.delete(redisKey);
        return true;
    }
}




